﻿using System;
using Microsoft.VisualStudio.Shell.Interop;

namespace VsxToolset
{
  // ==================================================================================
  /// <summary>
  /// This class is a wrapper class around an IVsOutputWindowPane instance to manage
  /// output handling for the window pane.
  /// </summary>
  // ==================================================================================
  public sealed class OutputWindowPane
  {
    #region Private fields

    private readonly OutputPaneDefinition _PaneDefinition;
    private readonly IVsOutputWindowPane _Pane;
    private bool _ThreadSafe;
    private string _Name;

    #endregion

    #region Lifecycle methods

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Creates an output pane instance using the specified output pane definition and 
    /// IVsOutputWindowPane instance.
    /// </summary>
    /// <param name="paneDef">Pane definition instance</param>
    /// <param name="pane">Physical output window pane</param>
    /// <remarks>
    /// This constructor is to be used only by the OutputWindow class.
    /// </remarks>
    // --------------------------------------------------------------------------------
    internal OutputWindowPane(OutputPaneDefinition paneDef, IVsOutputWindowPane pane)
    {
      _PaneDefinition = paneDef;
      _ThreadSafe = paneDef.ThreadSafe;
      _Name = paneDef.Name;
      _Pane = pane;
    }

    #endregion

    #region Public properties

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Gets or sets the flag indicating if writes to the output window pane are 
    /// thread safe or not.
    /// </summary>
    // --------------------------------------------------------------------------------
    public bool ThreadSafe
    {
      get { return _ThreadSafe; }
      set { _ThreadSafe = value; }
    }

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Gets or sets the name of the output window pane.
    /// </summary>
    // --------------------------------------------------------------------------------
    public string Name
    {
      get
      {
        if (IsVirtual) return _Name;
        string name = string.Empty;
        _Pane.GetName(ref name);
        return name;
      }
      set
      {
        if (IsVirtual)
          _Name = value;
        else
        _Pane.SetName(value);
      }
    }

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Checks if this output pane is virtual or not.
    /// </summary>
    // --------------------------------------------------------------------------------
    public bool IsVirtual
    {
      get { return _PaneDefinition == null || _PaneDefinition.IsSilent || _Pane == null; }
    }

    #endregion 

    #region Public methods

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Activates this output window pane, shows the pane in the output window.
    /// </summary>
    // --------------------------------------------------------------------------------
    public void Activate()
    {
      if (IsVirtual) return;
      _Pane.Activate();
    }

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Hides this output window pane, undisplays it in the output window.
    /// </summary>
    // --------------------------------------------------------------------------------
    public void Hide()
    {
      if (IsVirtual) return;
      _Pane.Hide();
    }

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Clears the content of the output window pane.
    /// </summary>
    // --------------------------------------------------------------------------------
    public void Clear()
    {
      if (IsVirtual) return;
      _Pane.Clear();
    }

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Writes the specified string to the output of this window pane.
    /// </summary>
    /// <param name="output">String to send to the output.</param>
    /// <remarks>
    /// This operation is thread safe or not according to the ThreadSafe property. If
    /// the output window pane is silent, output is not send to any physical pane.
    /// </remarks>
    // --------------------------------------------------------------------------------
    public void Write(string output)
    {
      OutputString(output);
    }

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Writes the specified formatted string to the output of this window pane.
    /// </summary>
    /// <param name="format">Format string to describe the output.</param>
    /// <param name="parameters">
    /// Parameters to be substituted into the format string.
    /// </param>
    /// <remarks>
    /// This operation is thread safe or not according to the ThreadSafe property. If
    /// the output window pane is silent, format is not send to any physical pane.
    /// </remarks>
    // --------------------------------------------------------------------------------
    public void Write(string format, params object[] parameters)
    {
      OutputString(string.Format(format, parameters));
    }

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Writes the specified formatted string using the specified provider to the 
    /// output of this window pane.
    /// </summary>
    /// <param name="provider">Format provider</param>
    /// <param name="format">Format string to describe the output.</param>
    /// <param name="parameters">
    /// Parameters to be substituted into the format string.
    /// </param>
    /// <remarks>
    /// This operation is thread safe or not according to the ThreadSafe property. If
    /// the output window pane is silent, format is not send to any physical pane.
    /// </remarks>
    // --------------------------------------------------------------------------------
    public void Write(IFormatProvider provider, string format, params object[] parameters)
    {
      OutputString(string.Format(provider, format, parameters));
    }

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Writes the specified string and a new line character to the output of this 
    /// window pane.
    /// </summary>
    /// <param name="output">String to send to the output.</param>
    /// <remarks>
    /// This operation is thread safe or not according to the ThreadSafe property. If
    /// the output window pane is silent, output is not send to any physical pane.
    /// </remarks>
    // --------------------------------------------------------------------------------
    public void WriteLine(string output)
    {
      OutputString(output + "\n");
    }

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Writes the specified formatted string and a new line character to the output 
    /// of this window pane.
    /// </summary>
    /// <param name="format">Format string to describe the output.</param>
    /// <param name="parameters">
    /// Parameters to be substituted into the format string.
    /// </param>
    /// <remarks>
    /// This operation is thread safe or not according to the ThreadSafe property. If
    /// the output window pane is silent, format is not send to any physical pane.
    /// </remarks>
    // --------------------------------------------------------------------------------
    public void WriteLine(string format, params object[] parameters)
    {
      OutputString(string.Format(format + "\n", parameters));
    }

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Writes the specified formatted string and a new line character using the 
    /// specified provider to the output of this window pane.
    /// </summary>
    /// <param name="provider">Format provider</param>
    /// <param name="format">Format string to describe the output.</param>
    /// <param name="parameters">
    /// Parameters to be substituted into the format string.
    /// </param>
    /// <remarks>
    /// This operation is thread safe or not according to the ThreadSafe property. If
    /// the output window pane is silent, format is not send to any physical pane.
    /// </remarks>
    // --------------------------------------------------------------------------------
    public void WriteLine(IFormatProvider provider, string format, 
      params object[] parameters)
    {
      OutputString(string.Format(provider, format + "\n", parameters));
    }

    #endregion

    #region Private methods

    // --------------------------------------------------------------------------------
    /// <summary>
    /// Outputs the specified string to this window pane.
    /// </summary>
    /// <param name="output">String to send to the output.</param>
    // --------------------------------------------------------------------------------
    private void OutputString(string output)
    {
      if (IsVirtual) return;
      if (_PaneDefinition.ThreadSafe)
        _Pane.OutputStringThreadSafe(output);
      else
        _Pane.OutputString(output);
    }

    #endregion
  }
}
